/*! * UX4G Accessibility beta v1.12.0 (https://doc.ux4g.gov.in/) * Copyright 2025 The UX4G Authors(Vipul Agarwal, Ershad Alam, Suman Prasad) * Copyright 2025 NeGD, MeitY. * Licensed under MIT. */ (function () { const SETTINGS_KEY = "accessibilitySettings"; // Function to get cookie domain dynamically function getCookieDomain() { const hostname = location.hostname; // For localhost or IP addresses, return empty string if (hostname === 'localhost' || /^\d+\.\d+\.\d+\.\d+$/.test(hostname)) { return ''; } // For regular domains, prepend with dot for cross-subdomain access const parts = hostname.split('.'); if (parts.length > 1) { return '.' + parts.slice(1).join('.'); // ".example.co.in" } } const widgetHTML = ` UX4G Accessibility Tool `; document.body.insertAdjacentHTML('beforeend', widgetHTML); document.addEventListener("DOMContentLoaded", loadSettings); document.addEventListener("scroll", function () { detectRouteChange() }) document.getElementById('uw-widget-custom-trigger').addEventListener('click', function () { document.getElementById('uw-main').style.right = '0'; }); function closeMain() { document.getElementById('uw-main').style.right = '-530px'; } document.addEventListener('DOMContentLoaded', function () { const closeButtons = document.querySelectorAll('.uwaw-close'); closeButtons.forEach(function(button) { button.addEventListener('click', closeMain); }); }); let fontSizeCount = 0; let lineHeightCount = 0; let textSpacingCount = 0; let lastPath = window.location.pathname; let screenReader = false; const fontSizeSpans = document.querySelectorAll('#featureSteps span'); const lineHeightSpans = document.querySelectorAll('#featureSteps-lh span'); const textSpacingSpans = document.querySelectorAll('#featureSteps-ts span'); let speechSynthesisInstance = window.speechSynthesis; let tabPressCount = 0; // Function to Speak Text function speakText(text) { if (!text.trim()) return; // Prevent empty speech const utterance = new SpeechSynthesisUtterance(text); utterance.lang = "en-US"; utterance.rate = 1; speechSynthesisInstance.cancel(); speechSynthesisInstance.speak(utterance); } // Detect Tab Key Press and Announce Accessibility Menu document.addEventListener("keydown", (event) => { if (event.key === "Tab") { tabPressCount++; if (tabPressCount === 2) { speakText("Press Enter to open accessibility menu."); } } else if (event.key === "Enter" && tabPressCount === 2) { speakText("Opening accessibility menu."); tabPressCount = 0; } }); // Reset Tab Count on Mouse Click document.addEventListener("click", (event) => { tabPressCount = 0; let element = event.target; let clickedText = ""; if (element.tagName === "IMG") { clickedText = element.getAttribute("alt") || element.getAttribute("aria-label") || element.getAttribute("title") || "Clickable image"; } else { clickedText = element.innerText.trim(); } if (clickedText && screenReader) { speakText(clickedText); } }); document.addEventListener("mouseup", () => { let selectedText = window.getSelection().toString(); if (selectedText && screenReader) { speakText(selectedText); } }); // Speak Element's Name on Hover document.addEventListener("mouseover", (event) => { let element = event.target; let textToSpeak = ""; if (element.tagName === "IMG" && element.closest("A, BUTTON")) { textToSpeak = element.getAttribute("alt") || element.getAttribute("aria-label") || element.getAttribute("title") || "Clickable image"; } else if (element.tagName === "A" || element.tagName === "BUTTON" || element.tagName === "INPUT" || element.tagName === "TEXTAREA" || element.hasAttribute("role")) { textToSpeak = element.innerText || element.getAttribute("aria-label") || element.getAttribute("alt") || element.value || "Interactive element"; } if (textToSpeak && screenReader) { speechSynthesisInstance.cancel(); speakText(textToSpeak); } }); function toggleTextToSpeech() { const tickIcon = document.getElementById('tickIcon_sp'); const button = document.getElementById('featureItem_sp'); button.classList.toggle('feature-active'); tickIcon.style.display = tickIcon.style.display === 'inline-flex' ? 'none' : 'inline-flex'; screenReader = !screenReader; saveSettings(); if (speechSynthesis.speaking) { speechSynthesis.cancel(); } } document.addEventListener('DOMContentLoaded', function () { const speakButton = document.getElementById('speak'); if (speakButton) { speakButton.addEventListener('click', toggleTextToSpeech); } }); function updateLineHeight() { document.querySelectorAll('body *:not(.uwaw *):not(.uwaw)').forEach((el) => { let currentSize = parseFloat(window.getComputedStyle(el).lineHeight) || parseFloat(window.getComputedStyle(el).fontSize) * 1.2; el.style.lineHeight = (currentSize + 1) + 'px'; }); } function updateLetterSpacing() { document.querySelectorAll('body *:not(.uwaw *):not(.uwaw)').forEach((el) => { el.style.letterSpacing = (textSpacingCount * .12) + 'em'; el.style.wordSpacing = (.16 * textSpacingCount) + 'em'; }); } function applyTextSettings() { let elements = document.querySelectorAll('body > *:not(.uwaw)'); elements.forEach(el => { let currentZoom = parseFloat(el.style.zoom) || 1; el.style.zoom = (currentZoom + 0.1).toFixed(2); }); } function adjustFontSize() { const button = document.getElementById('featureItem'); const tickIcon = document.getElementById('tickIcon'); const fontCheck = document.getElementById('featureSteps'); button.classList.add('feature-active'); fontSizeCount = (fontSizeCount + 1) % 5; applyTextSettings(); saveSettings(); if (fontSizeCount === 0) { button.classList.remove('feature-active'); tickIcon.style.display = 'none'; fontCheck.classList.remove('featureSteps-visible'); document.querySelectorAll('body > *:not(.uwaw)').forEach(el => el.style.zoom = 1); fontSizeSpans.forEach(span => span.classList.remove('active')); } else { tickIcon.style.display = 'inline-flex'; fontCheck.classList.add('featureSteps-visible'); fontSizeSpans.forEach(span => span.classList.remove('active')); fontSizeSpans.forEach((span, index) => { if (index <= fontSizeCount - 1) { span.classList.add('active'); } }); } } document.addEventListener('DOMContentLoaded', function () { const fontSizeBtn = document.getElementById('btn-s9'); if (fontSizeBtn) { fontSizeBtn.addEventListener('click', adjustFontSize); } }); function adjustLineHeight() { const button = document.getElementById('featureItem-lh'); const tickIcon = document.getElementById('tickIcon-lh'); const lineHeightCheck = document.getElementById('featureSteps-lh'); button.classList.add('feature-active'); lineHeightCount = (lineHeightCount + 1) % 5; updateLineHeight(); saveSettings(); if (lineHeightCount === 0) { button.classList.remove('feature-active'); tickIcon.style.display = 'none'; lineHeightCheck.classList.remove('featureSteps-visible'); document.querySelectorAll('body *:not(.uwaw *):not(.uwaw)').forEach((el) => { el.style.lineHeight = ""; }); lineHeightSpans.forEach(span => span.classList.remove('active')); } else { tickIcon.style.display = 'inline-flex'; lineHeightSpans.forEach(span => span.classList.remove('active')); lineHeightSpans.forEach((span, index) => { if (index <= lineHeightCount - 1) { span.classList.add('active'); } }); lineHeightCheck.classList.add('featureSteps-visible'); } } document.addEventListener('DOMContentLoaded', function () { const lineHeightBtn = document.getElementById('btn-s12'); if (lineHeightBtn) { lineHeightBtn.addEventListener('click', adjustLineHeight); } }); function adjustTextSpacing() { const button = document.getElementById('featureItem-ts'); button.classList.add('feature-active'); textSpacingCount = (textSpacingCount + 1) % 4; updateLetterSpacing(); saveSettings(); const tickIcon = document.getElementById('tickIcon-ts'); const textSpacingCheck = document.getElementById('featureSteps-ts'); if (textSpacingCount === 0) { button.classList.remove('feature-active'); tickIcon.style.display = 'none'; textSpacingCheck.classList.remove('featureSteps-visible'); document.querySelectorAll('body *:not(.uwaw *):not(.uwaw)').forEach(el => { el.style.letterSpacing = ""; }); textSpacingSpans.forEach(span => span.classList.remove('active')); } else { tickIcon.style.display = 'inline-flex'; textSpacingSpans.forEach(span => span.classList.remove('active')); textSpacingSpans.forEach((span, index) => { if (index <= textSpacingCount - 1) { span.classList.add('active'); } }); textSpacingCheck.classList.add('featureSteps-visible'); } } document.addEventListener('DOMContentLoaded', function () { const spacingBtn = document.getElementById('btn-s13'); if (spacingBtn) { spacingBtn.addEventListener('click', adjustTextSpacing); } }); function toggleHighlightLinks() { const button = document.getElementById('featureItem-ht'); const tickIcon = document.getElementById('tickIcon-ht'); button.classList.toggle('feature-active'); tickIcon.style.display = tickIcon.style.display === 'inline-flex' ? 'none' : 'inline-flex'; document.body.classList.toggle('highlight-links'); let tool = document.querySelector('.uwaw'); if (tool) { tool.classList.remove('highlight-links'); } saveSettings(); } document.addEventListener('DOMContentLoaded', function () { const highlightBtn = document.getElementById('btn-s10'); if (highlightBtn) { highlightBtn.addEventListener('click', toggleHighlightLinks); } }); function toggleDyslexiaMode() { const button = document.getElementById('featureItem-df'); const tickIcon = document.getElementById('tickIcon-df'); button.classList.toggle('feature-active'); tickIcon.style.display = tickIcon.style.display === 'inline-flex' ? 'none' : 'inline-flex'; document.body.classList.toggle('dyslexia-mode'); saveSettings(); } document.addEventListener('DOMContentLoaded', function () { const dyslexiaBtn = document.getElementById('btn-df'); if (dyslexiaBtn) { dyslexiaBtn.addEventListener('click', toggleDyslexiaMode); } }); function hideImages() { const button = document.getElementById('featureItem-hi'); const tickIcon = document.getElementById('tickIcon-hi'); button.classList.toggle('feature-active'); tickIcon.style.display = tickIcon.style.display === 'inline-flex' ? 'none' : 'inline-flex'; document.body.classList.toggle('hide-images'); saveSettings(); } document.addEventListener('DOMContentLoaded', function () { const hideImagesBtn = document.getElementById('btn-s11'); if (hideImagesBtn) { hideImagesBtn.addEventListener('click', hideImages); } }); function changeCursor() { const button = document.getElementById('featureItem-Cursor'); const tickIcon = document.getElementById('tickIcon-cursor'); button.classList.toggle('feature-active'); tickIcon.style.display = tickIcon.style.display === 'inline-flex' ? 'none' : 'inline-flex'; document.body.classList.toggle('custom-cursor'); saveSettings(); } document.addEventListener('DOMContentLoaded', function () { const cursorBtn = document.getElementById('btn-cursor'); if (cursorBtn) { cursorBtn.addEventListener('click', changeCursor); } }); function toggleDarkMode() { const button = document.getElementById('featureItem-ht-dark'); const tickIcon = document.getElementById('tickIcon-ht-dark'); button.classList.toggle('feature-active'); tickIcon.style.display = tickIcon.style.display === 'inline-flex' ? 'none' : 'inline-flex'; document.body.classList.toggle('dark-mode'); saveSettings(); } document.addEventListener('DOMContentLoaded', function () { const darkModeBtn = document.getElementById('dark-btn'); if (darkModeBtn) { darkModeBtn.addEventListener('click', toggleDarkMode); } }); function invertColor() { const button = document.getElementById('featureItem-ic'); const tickIcon = document.getElementById('tickIcon-ic'); button.classList.toggle('feature-active'); tickIcon.style.display = tickIcon.style.display === 'inline-flex' ? 'none' : 'inline-flex'; document.documentElement.classList.toggle('invert-colors'); saveSettings(); } document.addEventListener('DOMContentLoaded', function () { const invertBtn = document.getElementById('btn-invert'); if (invertBtn) { invertBtn.addEventListener('click', invertColor); } }); function applyADHDFriendlyMode() { const allTextNodes = document.body.querySelectorAll( 'p:not(.uwaw *), h1:not(.uwaw *), h2:not(.uwaw *), h3:not(.uwaw *), h4:not(.uwaw *), h5:not(.uwaw *), h6:not(.uwaw *), span:not(.uwaw *), li:not(.uwaw *), a:not(.uwaw *)' ); allTextNodes.forEach(node => { if (node.nodeType === Node.TEXT_NODE && node.textContent.trim().length > 0) { let text = node.textContent; let updatedText = text.replace(/\b([a-zA-Z0-9]+)\b/g, (match) => { if (/|/.test(match)) return match; let word = match; if (word.length % 2 === 0) { let halfLength = Math.floor(word.length / 2); return `${word.substring(0, halfLength)}${word.substring(halfLength)}`; } else { let halfLength = Math.floor(word.length / 2) + 1; return `${word.substring(0, halfLength)}${word.substring(halfLength)}`; } }); let tempDiv = document.createElement('div'); tempDiv.innerHTML = updatedText; node.replaceWith(...tempDiv.childNodes); } else if (node.nodeType === Node.ELEMENT_NODE) { const childNodes = node.childNodes; childNodes.forEach(childNode => { if (childNode.nodeType === Node.TEXT_NODE && childNode.textContent.trim().length > 0) { let text = childNode.textContent; let updatedText = text.replace(/\b([a-zA-Z0-9]+)\b/g, (match) => { if (/|/.test(match)) return match; let word = match; if (word.length % 2 === 0) { let halfLength = Math.floor(word.length / 2); return `${word.substring(0, halfLength)}${word.substring(halfLength)}`; } else { let halfLength = Math.floor(word.length / 2) + 1; return `${word.substring(0, halfLength)}${word.substring(halfLength)}`; } }); let tempDiv = document.createElement('div'); tempDiv.innerHTML = updatedText; childNode.replaceWith(...tempDiv.childNodes); } }); } }); } window.toggleADHDFriendlyMode = function () { const button = document.getElementById('featureItem-adhd'); const tickIcon = document.getElementById('tickIcon-adhd'); button.classList.toggle('feature-active'); tickIcon.style.display = tickIcon.style.display === 'inline-flex' ? 'none' : 'inline-flex'; document.body.classList.toggle('adhd-friendly'); if (document.body.classList.contains('adhd-friendly')) { saveSettings(); applyADHDFriendlyMode(); } else { const allTextNodes = document.body.querySelectorAll( 'p:not(.uwaw *), h1:not(.uwaw *), h2:not(.uwaw *), h3:not(.uwaw *), h4:not(.uwaw *), h5:not(.uwaw *), h6:not(.uwaw *), span:not(.uwaw *), li:not(.uwaw *), a:not(.uwaw *)' ); allTextNodes.forEach(node => { node.innerHTML = node.innerHTML.replace(/(.*?)<\/span>/g, '$1'); }); saveSettings(); } }; function resetSettings() { const cookieDomain = getCookieDomain(); // Clear cookie with dynamic domain if (cookieDomain) { document.cookie = `${SETTINGS_KEY}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${cookieDomain}`; } else { // For localhost or IP addresses document.cookie = `${SETTINGS_KEY}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`; } speechSynthesisInstance.cancel(); const allTextNodes = document.body.querySelectorAll( 'p:not(.uwaw *), h1:not(.uwaw *), h2:not(.uwaw *), h3:not(.uwaw *), h4:not(.uwaw *), h5:not(.uwaw *), h6:not(.uwaw *), span:not(.uwaw *), li:not(.uwaw *), a:not(.uwaw *)' ); allTextNodes.forEach(node => { node.innerHTML = node.innerHTML.replace(/(.*?)<\/span>/g, '$1'); }); document.querySelectorAll('body *:not(.uwaw *):not(.uwaw)').forEach((el) => { el.style.letterSpacing = ""; el.style.wordSpacing = ""; el.style.fontSize = ""; el.style.lineHeight = ""; el.style.cursor = ""; el.style.zoom = "1"; el.classList.remove("active"); }); document.body.classList.remove( "dark-mode", "adhd-friendly", "custom-cursor", "dyslexia-mode", "highlight-links", "hide-images" ); document.documentElement.classList.remove("invert-colors"); fontSizeCount = 0; lineHeightCount = 0; textSpacingCount = 0; screenReader = false; saveSettings(); loadSettings(); const checkboxes = document.querySelectorAll('.uwaw input[type="checkbox"]'); checkboxes.forEach(checkbox => checkbox.checked = false); document.querySelectorAll('.font-size-visible, .line-height-visible, .text-spacing-visible') .forEach(el => el.classList.remove('span-visible')); } document.addEventListener('DOMContentLoaded', function () { const resetBtn = document.getElementById('reset-all'); if (resetBtn) { resetBtn.addEventListener('click', resetSettings); } }); function getCookie(name) { const value = "; " + document.cookie; const parts = value.split("; " + name + "="); if (parts.length === 2) return decodeURIComponent(parts.pop().split(";").shift()); } function saveSettings() { const settings = { screenReader: screenReader, fontSizeCount: fontSizeCount - 1, lineHeightCount: lineHeightCount - 1, textSpacingCount: textSpacingCount - 1, highlightLinks: document.body.classList.contains('highlight-links'), dyslexiaMode: document.body.classList.contains('dyslexia-mode'), hideImages: document.body.classList.contains('hide-images'), darkMode: document.body.classList.contains('dark-mode'), cursorChanged: document.body.classList.contains('custom-cursor'), invert: document.documentElement.classList.contains('invert-colors'), adhdFriendly: document.body.classList.contains('adhd-friendly') }; const jsonStr = JSON.stringify(settings); const expiryDate = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toUTCString(); // 30 days const cookieDomain = getCookieDomain(); console.log(cookieDomain); // Check if running on HTTPS if (location.protocol === 'https:') { if (cookieDomain) { // For production domains with HTTPS document.cookie = `accessibilitySettings=${encodeURIComponent(jsonStr)}; expires=${expiryDate}; path=/; domain=${cookieDomain}; SameSite=Strict; Secure`; } else { // For localhost/IP with HTTPS document.cookie = `accessibilitySettings=${encodeURIComponent(jsonStr)}; expires=${expiryDate}; path=/; SameSite=Strict; Secure`; } } else { // Fallback for HTTP (development) if (cookieDomain) { document.cookie = `accessibilitySettings=${encodeURIComponent(jsonStr)}; expires=${expiryDate}; path=/; domain=${cookieDomain}`; } else { document.cookie = `accessibilitySettings=${encodeURIComponent(jsonStr)}; expires=${expiryDate}; path=/`; } console.warn("⚠️ Secure cookie attribute skipped (not HTTPS)"); } console.log("✅ Cookie saved for domain:", cookieDomain || 'current domain'); } function updateWidgetToggles(settings) { const speakOn = document.getElementById('tickIcon_sp'); if (speakOn) { speakOn.style.display = settings.screenReader ? 'inline-flex' : 'none'; } const highlightToggle = document.getElementById('tickIcon-ht'); if (highlightToggle) { highlightToggle.style.display = settings.highlightLinks ? 'inline-flex' : 'none'; } const darkModeToggle = document.getElementById('tickIcon-ht-dark'); if (darkModeToggle) { darkModeToggle.style.display = settings.darkMode ? 'inline-flex' : 'none'; } const invertToggle = document.getElementById('tickIcon-ic'); if (invertToggle) { invertToggle.style.display = settings.invert ? 'inline-flex' : 'none'; } const dyslexiaToggle = document.getElementById('tickIcon-df'); if (dyslexiaToggle) { dyslexiaToggle.style.display = settings.dyslexiaMode ? 'inline-flex' : 'none'; } const adhdToggle = document.getElementById('tickIcon-adhd'); if (adhdToggle) { adhdToggle.style.display = settings.adhdFriendly ? 'inline-flex' : 'none'; } const hideImagesToggle = document.getElementById('tickIcon-hi'); if (hideImagesToggle) { hideImagesToggle.style.display = settings.hideImages ? 'inline-flex' : 'none'; } const cursorToggle = document.getElementById('tickIcon-cursor'); if (cursorToggle) { cursorToggle.style.display = settings.cursorChanged ? 'inline-flex' : 'none'; } adjustFontSize(); adjustLineHeight(); adjustTextSpacing(); } function loadSettings() { let settings = getCookie(SETTINGS_KEY); if (!settings) { settings = getCookie(SETTINGS_KEY); } console.log(settings); if (settings) { settings = JSON.parse(settings); fontSizeCount = settings.fontSizeCount || 0; lineHeightCount = settings.lineHeightCount || 0; textSpacingCount = settings.textSpacingCount || 0; if (settings.screenReader) { screenReader = true; const button = document.getElementById('featureItem_sp'); button.classList.add('feature-active'); } else { const button = document.getElementById('featureItem_sp'); button.classList.remove('feature-active'); } if (settings.highlightLinks) { document.body.classList.add('highlight-links'); const button = document.getElementById('featureItem-ht'); button.classList.add('feature-active'); } else { const button = document.getElementById('featureItem-ht'); button.classList.remove('feature-active'); } if (settings.dyslexiaMode) { document.body.classList.add('dyslexia-mode'); const button = document.getElementById('featureItem-df'); button.classList.add('feature-active'); } else { const button = document.getElementById('featureItem-df'); button.classList.remove('feature-active'); } if (settings.hideImages) { document.body.classList.add('hide-images'); const button = document.getElementById('featureItem-hi'); button.classList.add('feature-active'); } else { const button = document.getElementById('featureItem-hi'); button.classList.remove('feature-active'); } if (settings.darkMode) { document.body.classList.add('dark-mode'); const button = document.getElementById('featureItem-ht-dark'); button.classList.add('feature-active'); } else { const button = document.getElementById('featureItem-ht-dark'); button.classList.remove('feature-active'); } if (settings.cursorChanged) { document.body.classList.add('custom-cursor'); const button = document.getElementById('featureItem-Cursor'); button.classList.add('feature-active'); } else { const button = document.getElementById('featureItem-Cursor'); button.classList.remove('feature-active'); } if (settings.invert) { document.documentElement.classList.add("invert-colors"); const button = document.getElementById('featureItem-ic'); button.classList.add('feature-active'); } else { const button = document.getElementById('featureItem-ic'); button.classList.remove('feature-active'); } if (settings.adhdFriendly) { document.body.classList.add('adhd-friendly'); applyADHDFriendlyMode(); } for (let i = 0; i < fontSizeCount; i++) { applyTextSettings(); } for (let i = 0; i < lineHeightCount; i++) { updateLineHeight(); } for (let i = 0; i < textSpacingCount; i++) { updateLetterSpacing(); } updateWidgetToggles(settings); } } function detectRouteChange() { const settings = JSON.parse(localStorage.getItem(SETTINGS_KEY)); const settingsStr = JSON.parse(getCookie(SETTINGS_KEY)); console.log(settings, settingsStr); setInterval(() => { let currentPath = window.location.pathname; if (currentPath !== lastPath) { speechSynthesisInstance.cancel(); lastPath = currentPath; if (settings?.adhdFriendly || settingsStr?.adhdFriendly) { document.body.classList.add('adhd-friendly'); applyADHDFriendlyMode(); } for (let i = 0; i < lineHeightCount; i++) { updateLineHeight(); } updateLetterSpacing(); } }, 1000); } })();